gusucode.com > VC++ 界面很酷的一款多媒体播放器 > VC++ 界面很酷的一款多媒体播放器/gusucode/xMedia代码注释中/playlist.cpp

    //Download by http://www.NewXing.com
/****************************************
*	File:			playlist.cpp		*
*	Last modified:	2004.2.15			*
*	Author:			Yuanyi-Zhang		*
*	Version:		0.0.1.0				*
*	CopyLeft 2004   xMedia team			*
****************************************/
/****************************************************************
*																*
* This file may be distributed and/or modified under the terms	*
* of the GNU General Public License version 2 as published by	*
* the Free Software Foundation and appearing in the file		*
* LICENSE.GPL included in the packaging of this file.			*
*																*
****************************************************************/

#pragma warning(disable:4786)

#include <tchar.h>
#include <windows.h>
#include <commctrl.h>
#include <shlobj.h>
#include <assert.h>

#include <fstream>

#include "util.h"
#include "messagedef.h"
#include "playlist.h"

//////////////////////////////////
PlayList::PlayList(): m_hWnd( NULL ), m_ErrorString( _T("") ), 
			m_HasCreated(false), m_ClassName( _T("PlayList") ),
			m_lpIL(0), m_LButtonDown(false), m_Show(false)
{
	m_hDCBack = NULL;
	m_hBmpBack = NULL;
	m_hMainBmp = NULL;
	m_hMaskBmp = NULL;
	m_hElemBmp = NULL;
	m_curNum = -1;
	m_hMenuAdd = m_hMenuRem = m_hMenuLOP = m_hMenuSel = NULL;

	_tcscpy( tInitDir, _T("") );
}
/////////////////////////////
//注册窗口类
BOOL PlayList::RegisterClass( HINSTANCE hInstance )
{
	WNDCLASSEX	wndclass;

	ZeroMemory(&wndclass, sizeof(wndclass));

	//Window class for the main application parent window
	wndclass.cbSize			= sizeof(wndclass);
	wndclass.style			= 0;
	wndclass.lpfnWndProc	= WndProc;
	wndclass.cbClsExtra		= 0;
	wndclass.cbWndExtra		= 0;
	wndclass.hInstance		= hInstance;
	wndclass.hIcon			= 0;
	wndclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);
	wndclass.lpszMenuName	= 0;
	wndclass.lpszClassName	= m_ClassName.c_str();
	wndclass.hIconSm		= 0;

	return RegisterClassEx(&wndclass);
}
//////////////////////////////////
//创建播放列表
bool PlayList::Create( HINSTANCE hInstance, HWND Parent)
{
	if( m_HasCreated )
	{
		m_ErrorString=_T("错误,重复创建主窗口!");
		return false;
	}

	if( !RegisterClass( hInstance ) )
	{
		m_ErrorString=_T("注册窗口类失败!");
		return false;
	}

	MDICREATESTRUCT mdic;
	memset(& mdic, 0, sizeof(mdic));
	mdic.lParam = (LPARAM) this;

	HWND hWnd=CreateWindowEx( WS_EX_TOOLWINDOW,
		m_ClassName.c_str(), NULL,
		WS_POPUP|LVS_EX_ONECLICKACTIVATE, 
		0, 0, 100, 100,
		Parent, 0,
		hInstance, &mdic );

	if(hWnd==NULL)
	{
		m_ErrorString = _T( "创建播放列表失败,不明错误!" );
		return false;
	}
	
	if( !InitTooltips( hWnd, hInstance ) )
	{
		return false;
	}

	m_ErrorString = _T( "" );
	return true;
}
/////////////////////////////////////
//读取皮肤配置
bool PlayList::LoadSkinConfig()
{
	if( m_lpIL == NULL )
	{
		m_ErrorString = _T("未设置配置文件");
		return false;
	}

	string	str;

	str = m_lpIL->Get( _T( "plwindowrect" ) );

	if( str.compare( _T( "" ) ) == 0 )
	{
		m_ErrorString = _T("配置文件不完整,无法读取所需信息!");
		return false;
	}

	m_WndRect = StringToRect( str );

	str = m_lpIL->Get( _T( "pllistwndrect" ) );

	if( str.compare( _T( "" ) ) == 0 )
	{
		m_ErrorString = _T("配置文件不完整,无法读取所需信息!");
		return false;
	}

	m_ListRect = StringToRect( str );

	str = m_lpIL->Get( _T( "pllistwndbkcolor" ) );

	if( str.compare( _T( "" ) ) == 0 )
	{
		m_ErrorString = _T("配置文件不完整,无法读取所需信息!");
		return false;
	}

	m_ListBkColor = StringToColorRef( str );

	str = m_lpIL->Get( _T( "pllistwndfontcolor" ) );

	if( str.compare( _T( "" ) ) == 0 )
	{
		m_ErrorString = _T("配置文件不完整,无法读取所需信息!");
		return false;
	}

	m_ListFontColor = StringToColorRef( str );

	m_SkinName = m_lpIL->Get( _T( "skinname" ) );

	m_vecElement.push_back( Element( _T("plclosebutton"), m_lpIL, XM_PLCLOSEBUTTON, true ) );
	m_vecElement.push_back( Element( _T("pladdbutton"), m_lpIL, XM_PLADDBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plrembutton"), m_lpIL, XM_PLREMBUTTON, true ) );
	m_vecElement.push_back( Element( _T("pllopbutton"), m_lpIL, XM_PLLOPBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plmiscbutton"), m_lpIL, XM_PLMISCBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plselbutton"), m_lpIL, XM_PLSELBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plplaybutton"), m_lpIL, XM_PLPLAYBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plnextbutton"), m_lpIL, XM_PLNEXTBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plpausebutton"), m_lpIL, XM_PLPAUSEBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plprevbutton"), m_lpIL, XM_PLPREVBUTTON, true ) );
	m_vecElement.push_back( Element( _T("plstopbutton"), m_lpIL, XM_PLSTOPBUTTON, true ) );

	return true;
}
//////////////////////////////////////
//将窗口消息发送到播放列表消息处理窗口
LRESULT CALLBACK PlayList::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam,
							 LPARAM lParam )
{
	PlayList *pMainWnd;
	if ( uMsg==WM_NCCREATE )
	{   
		assert( ! IsBadReadPtr((void *) lParam, sizeof(CREATESTRUCT)) );
		MDICREATESTRUCT * pMDIC = (MDICREATESTRUCT *) ((LPCREATESTRUCT) lParam)->lpCreateParams;

		pMainWnd = (PlayList *) (pMDIC->lParam);

		assert( ! IsBadReadPtr(pMainWnd, sizeof(PlayList)) );
		SetWindowLong(hWnd, GWL_USERDATA, (LONG) pMainWnd);
	}
	else
		pMainWnd=(PlayList *)GetWindowLong(hWnd, GWL_USERDATA);
	
	return pMainWnd->MsgProc( hWnd, uMsg, wParam, lParam );
}
//////////////////////////////////////////
//处理播放列表窗口消息
long PlayList::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	POINT p;
	switch( uMsg )
	{
	case WM_CREATE:
		m_hWnd = hWnd;
		if( !initials( hWnd ) )
		{
			MessageBox( hWnd, GetErrorString().c_str(), "错误", MB_OK|MB_ICONWARNING );
		}
		break;
	case WM_PAINT:
		onDraw();
		break;
	case WM_LBUTTONDOWN:
		SetCapture( hWnd );
		p.x = LOWORD(lParam);
		p.y = HIWORD(lParam);
		ClientToScreen( hWnd, &p );
		onLButtonDown( p );
		break;
	case WM_MOUSEMOVE:
		GetCursorPos( &p );
		onMouseMove( p );
		break;
	case WM_LBUTTONUP:
		ReleaseCapture();
		p.x = LOWORD(lParam);
		p.y = HIWORD(lParam);
		ClientToScreen( hWnd, &p );
		onLButtonUp( p );
		break;
	case WM_COMMAND:
		switch( LOWORD( wParam ) )
		{
		case IDM_ADDFILE:
			addFileToList();
			break;
		case IDM_ADDDIR:
			addDirToList();
			break;
		case IDM_REMALL:
			ListView_DeleteAllItems( m_hWndList );
			m_vecFile.erase( m_vecFile.begin(), m_vecFile.end() );
			break;
		case IDM_REMSEL:
			RemSel();
			break;
		case IDM_REMUNSEL:
			RemUnSel();
			break;
		case IDM_SELALL:
			SelAll();
			break;
		case IDM_UNSEL:
			UnSel();
			break;
		case IDM_SELOTHER:
			SelOther();
			break;
		case IDM_LOADLIST:
			loadList();
			break;
		case IDM_SAVELIST:
			saveList();
			break;
		}
		break;
	case WM_NOTIFY:
		switch (((LPNMHDR) lParam)->code) 
		{
		case LVN_ITEMACTIVATE:
			//有项目被双击则播放此项目
			ListView_SetHotItem( m_hWndList, ((LPNMLISTVIEW)lParam)->iItem );
			PostThreadMessage( GetCurrentThreadId(), MC_PLAY, 0l, 0l );
			break;
		}
		break;
	case XM_GETFILEINFO:
		getFileInfo();
		break;
	case XM_PLCLOSEBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			Show();
			break;
		}
		break;
	case XM_PLPLAYBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			PostThreadMessage( GetCurrentThreadId(), MC_PLAY, 0l, 0l );
			break;
		}
		break;
	case XM_PLSTOPBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			PostThreadMessage( GetCurrentThreadId(), MC_STOP, 0l, 0l );
			break;
		}
		break;
	case XM_PLPAUSEBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			PostThreadMessage( GetCurrentThreadId(), MC_PAUSE, 0l, 0l );
			break;
		}
		break;
	case XM_PLPREVBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			PostThreadMessage( GetCurrentThreadId(), MC_PLAYPREV, 0l, 0l );
			break;
		}
		break;
	case XM_PLNEXTBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			PostThreadMessage( GetCurrentThreadId(), MC_PLAYNEXT, 0l, 0l );
			break;
		}
		break;
	case XM_PLADDBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			popupMenu( m_hMenuAdd, _T("pladdbutton") );
			break;
		}
		break;
	case XM_PLREMBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			popupMenu( m_hMenuRem, _T("plrembutton") );
			break;
		}
		break;
	case XM_PLLOPBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			popupMenu( m_hMenuLOP, _T("pllopbutton") );
			break;
		}
		break;
	case XM_PLSELBUTTON:
		switch( wParam )
		{
		case ELEM_LBUTTONDOWN:
			popupMenu( m_hMenuSel, _T("plselbutton") );
			break;
		}
		break;
	}
	return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
		
//////////////////////////////////////
//初始化播放列表
bool PlayList::initials( HWND hwnd )
{
	if( !InitDC() )
	{
		return false;
	}
	
	SetWindowSize();

	if( !LoadResource() )
	{
		return false;
	}

	SetWindowRegion();

	if( !initMenu() )
	{
		return false;
	}

	if( !createList( hwnd ) )
	{
		return false;
	}

	m_HasCreated = true;
	return true;
}

//////////////////////////
//初始化DC 
bool PlayList::InitDC()
{
	if( m_hDCBack )
	{
		DeleteObject( m_hDCBack );
	}
	if( m_hBmpBack )
	{
		DeleteObject( m_hBmpBack );
	}

	HDC hdc;
	hdc = GetDC( m_hWnd );
	
	m_hDCBack = CreateCompatibleDC( hdc );
	m_hBmpBack = CreateCompatibleBitmap( hdc, 
		m_WndRect.right - m_WndRect.left,
		m_WndRect.bottom - m_WndRect.top);

	if( !m_hDCBack || !m_hBmpBack )
	{
		m_ErrorString = _T("初始化DC失败!");
		return false;
	}

	SelectObject( m_hDCBack, m_hBmpBack );
	return true;
}
///////////////////////	
//释放资源
void PlayList::ReleaseResource()
{
	if( m_hDCBack )
	{
		DeleteObject( m_hDCBack );
	}
	if( m_hBmpBack )
	{
		DeleteObject( m_hBmpBack );
	}
	if( m_hMaskBmp )
	{
		DeleteObject( m_hMaskBmp );
	}
	if( m_hMainBmp )
	{
		DeleteObject( m_hMainBmp );
	}
	if( m_hElemBmp )
	{
		DeleteObject( m_hElemBmp );
	}
	if( m_hMenuAdd)
	{
		DestroyMenu( m_hMenuAdd);
	}
	if( m_hMenuRem)
	{
		DestroyMenu( m_hMenuRem);
	}
	if( m_hMenuLOP)
	{
		DestroyMenu( m_hMenuLOP);
	}
	if( m_hMenuSel)
	{
		DestroyMenu( m_hMenuSel);
	}
}
////////////////////
//处理OnDraw消息
bool PlayList::onDraw( )
{
	HDC hdc,hdcImg;
	PAINTSTRUCT ps;
	hdc = BeginPaint( m_hWnd, &ps );

	hdcImg = CreateCompatibleDC( hdc );
	SelectObject( hdcImg, m_hMainBmp );
	BitBlt( m_hDCBack, 0, 0,
		m_WndRect.right - m_WndRect.left,
		m_WndRect.bottom - m_WndRect.top,
		hdcImg, 0, 0, SRCCOPY );

	vector<Element>::iterator ite;

	for( ite = m_vecElement.begin(); ite != m_vecElement.end(); ite++ )
	{
		if( !ite->onDraw( m_hDCBack, m_hElemBmp ) )
		{
			return false;
		}
	}

	BitBlt( hdc, 0, 0, m_WndRect.right - m_WndRect.left,
			m_WndRect.bottom - m_WndRect.top, m_hDCBack, 
			0, 0, SRCCOPY );
	
	EndPaint( m_hWnd, &ps );

	DeleteObject( hdcImg );
	DeleteObject( hdc );

	return true;
}
////////////////////
//读取位图资源
bool PlayList::LoadResource()
{
	if( m_hMaskBmp )
	{
		DeleteObject( m_hMaskBmp );
	}
	if( m_hMainBmp )
	{
		DeleteObject( m_hMainBmp );
	}
	if( m_hElemBmp )
	{
		DeleteObject( m_hElemBmp );
	}

	string maskBmp,mainBmp,elemBmp;

	maskBmp = _T( "skin\\" ) + m_SkinName + _T( "\\plmask.bmp" );
	mainBmp = _T( "skin\\" ) + m_SkinName + _T( "\\plmain.bmp" );
	elemBmp = _T( "skin\\" ) + m_SkinName + _T( "\\plelement.bmp" );

	m_hMaskBmp = (HBITMAP)LoadImage( NULL, maskBmp.c_str(),
		IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION );

	if( !m_hMaskBmp )
	{
		m_ErrorString = _T("无法读取文件:") + maskBmp;
		return false;
	}
	
	m_hMainBmp = (HBITMAP)LoadImage( NULL, mainBmp.c_str(),
		IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION );

	if( !m_hMainBmp )
	{
		m_ErrorString = _T("无法读取文件:") + mainBmp;
		return false;
	}

	m_hElemBmp = (HBITMAP)LoadImage( NULL, elemBmp.c_str(),
		IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION );

	if( !m_hElemBmp )
	{
		m_ErrorString = _T("无法读取文件:") + elemBmp;
		return false;
	}

	return true;
}
////////////////////////////
//初始化工具提示
bool PlayList::InitTooltips( HWND hwnd, HINSTANCE hInst )
{
    HWND hwndTT;                 //Tooltip控件句柄

    //创建Tooltip控件
    hwndTT = CreateWindowEx(WS_EX_TOPMOST,
        TOOLTIPS_CLASS,
        NULL,
        WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,		
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        hwnd,
        NULL,
        hInst,
        NULL );
	
	if( hwndTT == NULL )
	{
		m_ErrorString = _T("创建工具提示窗口失败!");
		return false;
	}

    SetWindowPos(hwndTT,
        HWND_TOPMOST,
        0, 0, 0, 0,
        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

	//这个结构体存储Tooltip控件的相关信息
    TOOLINFO ti;
	unsigned int uid = 0;   

	//初始化ti结构体成员
    ti.cbSize = sizeof(TOOLINFO);
    ti.uFlags = TTF_SUBCLASS;
    ti.hwnd = hwnd;
    ti.hinst = hInst;
    ti.uId = uid;

	TCHAR tcsTooltip[256];

	vector<Element>::iterator ite;
	RECT rect;
	string str;
    for( ite = m_vecElement.begin(); ite != m_vecElement.end(); ite++ )
	{
		rect = ite->getRectPos();
		str = ite->getTooltip();
		if( (rect.left == rect.right && rect.top == rect.bottom) ||
			str.compare( _T("") ) == 0 )
		{
			continue;
		}
		strcpy( tcsTooltip, str.c_str() );
		ti.lpszText = tcsTooltip;
	    ti.rect = rect;
		//添加工具提示
		SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);	
	}
	return true;
}
////////////////////////////
//设置窗口可见区域
void PlayList::SetWindowRegion()
{
	HRGN hWndRgn;
	RECT clientRect,wndRect;
	
	GetClientRect( m_hWnd, &clientRect );
	GetWindowRect( m_hWnd, &wndRect );

	POINT start = { 0, 0 };
	ClientToScreen( m_hWnd, &start );

	hWndRgn = CreateRectRgn( start.x - wndRect.left, 
		start.y - wndRect.top, 
		clientRect.right - clientRect.left + start.x - wndRect.left,
		clientRect.bottom - clientRect.top + start.y - wndRect.top );

	BITMAP bmp;
	GetObject(m_hMaskBmp, sizeof(bmp), &bmp);
	
	HRGN temp;

	HDC hdc = GetDC( m_hWnd );
	HDC hdcImg = CreateCompatibleDC( hdc );
	ReleaseDC( m_hWnd, hdc );

	SelectObject( m_hDCBack, m_hBmpBack );
	SelectObject( hdcImg, m_hMaskBmp );
	BitBlt( m_hDCBack, 0, 0,
		m_WndRect.right - m_WndRect.left,
		m_WndRect.bottom - m_WndRect.top,
		hdcImg, 0, 0, SRCCOPY );

	DeleteObject( hdcImg );

	for( int i = 0; i < bmp.bmWidth; i++ )
	{
		for( int j = 0; j < bmp.bmHeight; j++ )
		{
			if( GetPixel( m_hDCBack, i, j ) == RGB( 255, 255, 255 ) )
			{
				temp = CreateRectRgn( start.x - wndRect.left + i, 
					start.y - wndRect.top + j,
					start.x - wndRect.left + i + 1, 
					start.y - wndRect.top + j + 1 );
				CombineRgn( hWndRgn, hWndRgn, temp, RGN_XOR );
				DeleteObject( temp );
			}
		}
	}
	SetWindowRgn( m_hWnd, hWndRgn, false );
}
////////////////////////////
//处理鼠标左键按下消息
void PlayList::onLButtonDown( POINT p )
{
	m_LButtonDown = true;
	m_clickPos = p;
	bool isElemClicked = false;

	ScreenToClient( m_hWnd, &p );

	vector<Element>::iterator ite;
	RECT  validRect;
	for( ite = m_vecElement.begin(); ite != m_vecElement.end(); ite++ )
	{
		if( ite->onLButtonDown( p ) )
		{
			isElemClicked = true;
			validRect = ite->getRectPos();
			InvalidateRect( m_hWnd, &validRect, false );
		}
	}

	if( isElemClicked )
	{
		m_LButtonDown = false;
	}
}
//////////////////////////
//处理鼠标移动消息
void PlayList::onMouseMove( POINT p )
{
	RECT wndRect;
	GetWindowRect( m_hWnd, &wndRect );
	if( m_LButtonDown )
	{
		wndRect.left += p.x - m_clickPos.x;
		wndRect.right += p.x - m_clickPos.x;
		wndRect.bottom += p.y - m_clickPos.y;
		wndRect.top += p.y - m_clickPos.y;

		m_clickPos = p;

		MoveWindow(m_hWnd, wndRect.left, wndRect.top,
			wndRect.right - wndRect.left,
			wndRect.bottom - wndRect.top,
			true );
	}
	else
	{
		ScreenToClient( m_hWnd, &p );

		vector<Element>::iterator ite;
		RECT  validRect;
		for( ite = m_vecElement.begin(); ite != m_vecElement.end(); ite++ )
		{
			if( ite->onMouseMove( p ) )
			{
				validRect = ite->getRectPos();
				InvalidateRect( m_hWnd, &validRect, false );
			}
		}
	}
}
/////////////////////////
//处理鼠标左键松开消息
void PlayList::onLButtonUp( POINT p )
{
	if( m_LButtonDown )
	{
		m_LButtonDown = false;
	}
	else
	{
		ScreenToClient( m_hWnd, &p );
		vector<Element>::iterator ite;
		RECT  validRect;
		for( ite = m_vecElement.begin(); ite != m_vecElement.end(); ite++ )
		{
			if( ite->onLButtonUp( p ) )
			{
				validRect = ite->getRectPos();
				InvalidateRect( m_hWnd, &validRect, false );
			}
		}
	}
}
///////////////////////////////////
//通过按钮名称获取按钮
Element* PlayList::getElementByName( string str )
{
	vector<Element>::iterator ite;
	
	for( ite = m_vecElement.begin(); ite != m_vecElement.end(); ite++ )
	{
		if( str.compare( ite->getName() ) == 0 )
			break;
	}

	if( ite == m_vecElement.end() )
	{
		return NULL;
	}
	
	return ite;
}
///////////////////////////////////
//创建列表框控件
bool	PlayList::createList( HWND hwnd )
{
	HINSTANCE hInst = (HINSTANCE) GetWindowLong( hwnd, GWL_HINSTANCE );

	m_hWndList = CreateWindowEx( WS_EX_ACCEPTFILES|
			LVS_EX_FULLROWSELECT|LVS_EX_TWOCLICKACTIVATE,
			WC_LISTVIEW, _T(""), 
			WS_CHILD | LVS_REPORT |LVS_NOCOLUMNHEADER|
			WS_VISIBLE, 
			0,0,100,100,
			hwnd, NULL, hInst, NULL);

	if( m_hWndList == NULL )
	{
		m_ErrorString = _T("创建播放列表失败!");
		return false;
	}

	MoveWindow( m_hWndList, m_ListRect.left, m_ListRect.top,
		m_ListRect.right - m_ListRect.left,
		m_ListRect.bottom - m_ListRect.top,
		true );
	
	LV_COLUMN lvc;

	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvc.iSubItem = 1;
	lvc.pszText = _T("文件名");
	lvc.cx = m_ListRect.right -m_ListRect.left - 80;
	lvc.fmt = LVCFMT_LEFT;

	ListView_InsertColumn( m_hWndList, 0, &lvc );

	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvc.iSubItem = 1;
	lvc.pszText = _T("长度");
	lvc.cx = 60;
	lvc.fmt = LVCFMT_RIGHT;

	ListView_InsertColumn( m_hWndList, 1, &lvc);

	ListView_SetBkColor( m_hWndList, m_ListBkColor );
	ListView_SetTextBkColor( m_hWndList, m_ListBkColor );
	ListView_SetTextColor( m_hWndList, m_ListFontColor );

	return true;
}
//////////////////////////////
//初始化弹出菜单
bool PlayList::initMenu()
{
	m_hMenuAdd = CreatePopupMenu( );

	InsertMenu( m_hMenuAdd, -1, MF_BYCOMMAND,
			IDM_ADDFILE, _T("添加文件...") );
	InsertMenu( m_hMenuAdd, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_ADDDIR, _T("添加目录...") );

	m_hMenuRem = CreatePopupMenu( );

	InsertMenu( m_hMenuRem, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_REMALL, _T("删除全部...") );
	InsertMenu( m_hMenuRem, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_REMSEL, _T("删除选中..." ) );
	InsertMenu( m_hMenuRem, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_REMUNSEL, _T("删除未选...") );

	m_hMenuLOP = CreatePopupMenu( );

	InsertMenu( m_hMenuLOP, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_LOADLIST, _T("导入列表...") );
	InsertMenu( m_hMenuLOP, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_SAVELIST, _T("保存列表...") );

	m_hMenuSel = CreatePopupMenu( );

	InsertMenu( m_hMenuSel, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_SELALL, _T("全部选定...") );
	InsertMenu( m_hMenuSel, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_SELOTHER, _T("反向选定...") );
	InsertMenu( m_hMenuSel, -1, MF_BYCOMMAND|MF_BYPOSITION|MF_STRING,
			IDM_UNSEL, _T("取消选择...") );

	if( !m_hMenuAdd || !m_hMenuRem || !m_hMenuLOP 
		|| !m_hMenuSel )
	{
		m_ErrorString = _T( "初始化菜单失败!" );
		return false;
	}
	return true;
}
/////////////////////
//显示弹出菜单
void PlayList::popupMenu( HMENU hMenu, string e )
{
	Element *elem = getElementByName( e );

	if( elem == NULL )
	{
		return;
	}

	RECT rect = elem->getRectPos();
	POINT p;
	p.x = rect.right;
	p.y = rect.top;

	ClientToScreen( m_hWnd, &p );

	TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, p.x, p.y, 
			0, m_hWnd, &rect );
}
////////////////////////////
//检查用户选择的文件名后缀是否被支持
bool PlayList::IsValidFileName(string fname)
{
	string fext;
	size_t ip;
	ip = fname.find_last_of(".");
	if( ip == fname.npos)
		return false;
	fext = fname.substr(ip+1);

	TCHAR tMediaFilter[][5]={
		_T("wav"),
		_T("wma"),
		_T("wmv"),
		_T("asf"),
		_T("mpeg"),
		_T("avi"),
		_T("mov"),
		_T("aiff"),
		_T("au"),
		_T("snd"),
		_T("midi"),
		_T("MP3")
		};
	int num = 12;
	int i;
	for( i = 0; i < num; i++ )
	{
		if( _tcsicmp( tMediaFilter[i], fext.c_str() ) == 0 )
			return true;
	}

	return false;
}
////////////////////////////
//添加文件夹内的所有按钮到播放列表
void PlayList::AddDir(TCHAR* tPathName)
{
	TCHAR curDir[256];
	GetCurrentDirectory(256,curDir);
	SetCurrentDirectory(tPathName);
	TCHAR tFileName[MAX_PATH];

	HANDLE fileHandle;
	WIN32_FIND_DATA findData;

	fileHandle = FindFirstFile(_T("*.*"), 
		&findData );
	while ( fileHandle != INVALID_HANDLE_VALUE )
	{
		if( !(findData.dwFileAttributes &
			FILE_ATTRIBUTE_DIRECTORY))	
		{
			_stprintf(tFileName,_T("%s\\%s"),tPathName,
				findData.cFileName);
			if(IsValidFileName(tFileName))
			{
				m_vecFile.push_back( FileInfo( tFileName ) );
			}
		}
		else
		{
			if(strcmp(findData.cFileName,".")&&
				strcmp(findData.cFileName,".."))
			{
				_stprintf(tFileName,_T("%s\\%s"),tPathName,
					findData.cFileName);
				AddDir(tFileName);
			}
		}
		//打开下一文件
		if (!FindNextFile( fileHandle, &findData ))
			break;
	}
	FindClose( fileHandle );//关闭文件
	SetCurrentDirectory(curDir);
	PostThreadMessage( GetCurrentThreadId( ), XM_GETFILEINFO, 0, 0 );
}
/////////////////////////
//显示目录选择对话框
void PlayList::addDirToList()
{
	BROWSEINFO bs;
	LPITEMIDLIST lpdl;
	TCHAR tPathName[MAX_PATH];

	memset( &bs, 0, sizeof(bs) );
	bs.hwndOwner = m_hWnd;
	bs.pidlRoot = NULL;
	bs.pszDisplayName = tPathName;
	bs.lpszTitle = "请选择目录";
	bs.ulFlags = BIF_RETURNONLYFSDIRS;
	lpdl = SHBrowseForFolder(&bs);
	if( SHGetPathFromIDList( lpdl, tPathName ) )
	{
		AddDir( tPathName );
	}
}
/////////////////////////
//从文件读取播放列表
void PlayList::loadList()
{
	TCHAR fileName[MAX_PATH] = _T("");
	TCHAR tFilter[]=_T("播放列表(*.m3u)\0*.m3u;\0");
	
	if( !showOpenDialog( m_hWnd, fileName, tFilter, tInitDir ) )
		return;

	ListView_DeleteAllItems( m_hWndList );
	m_vecFile.erase( m_vecFile.begin(), m_vecFile.end() );

	ifstream in;
	in.open(fileName);

	TCHAR tBuffer[MAX_PATH];
	string strBuf,strTemp,strDriver,strDir;
	size_t ip;

	//获取M3U文件存放路径
	strBuf=fileName;
	ip=strBuf.find_first_of('\\');
	strDriver=strBuf.substr(0,ip);
	ip=strBuf.find_last_of('\\');
	strDir=strBuf.substr(0,ip);

	//读取第一行并判断是否是有效的M3U文件
	in.getline(tBuffer,MAX_PATH);

	if(_tcscmp(tBuffer,_T("#EXTM3U")))
		return;

	while(in.good())
	{
		//读取第一行
		in.getline(tBuffer,MAX_PATH);
		strBuf=tBuffer;

		//检查是否有冒号
		ip=strBuf.find_first_of(':');
		if(ip==strBuf.npos)
		{
			continue;
		}
		
		//检查行首是否为#EXTINF,不是则跳过此行
		strTemp=strBuf.substr(0,ip);
		strBuf=strBuf.substr(ip+1);
		if(strTemp.compare(_T("#EXTINF")))
			continue;
		
		//获取此项目播放时间及标题
		ip=strBuf.find_first_of(',');
		strTemp=strBuf.substr(0,ip);
		strBuf=strBuf.substr(ip+1);

		//获取文件实际存放路径
		in.getline(tBuffer,MAX_PATH);
		strBuf=tBuffer;

		//检查路径是否完全,如果不完全,则以M3U文件
		//的存放目录补全
		ip=strBuf.find_first_of('\\');
		if(ip==strBuf.npos)
		{
			strBuf=strDir+"\\"+strBuf;
		}
		ip=strBuf.find_first_of(':');
		if(ip==strBuf.npos)
		{
			strBuf=strDriver+strBuf;
		}

		//将其添加到播放列表中
		m_vecFile.push_back(strBuf);
	}
	in.close();

	PostThreadMessage( GetCurrentThreadId( ), XM_GETFILEINFO, 0, 0 );
}
/////////////////////////
//保存播放列表为。M3U文件
void PlayList::saveList( )
{
	TCHAR tFileName[MAX_PATH]=_T("");

	//得到要保存的文件名
	if(!ShowSaveDialog( m_hWnd ,tFileName))
	{
		return;
	}
	//保存用户选择的M3U文件
	ofstream out;
	out.open(tFileName);

	vector<FileInfo>::iterator ite;
	if(out.good())
	{
		//写入M3U文件标志
		out<<_T("#EXTM3U")<<endl;
		for(ite=m_vecFile.begin();ite!=m_vecFile.end();ite++)
		{	
			//写入项目信息
			out<<_T("#EXTINF:")<<0<<_T(",")<<ite->getFileName()<<endl
				<<ite->getPath()<<endl;
		}
	}
	out.close();
}
/////////////////////////
//添加文件到列表
void PlayList::addFileToList()
{
	TCHAR fileName[MAX_PATH*4] = _T("");
	TCHAR tFilter[]=_T("所有支持类型\0*.wav;*.wma;*.wmv;*.asf;*.mpeg;*.avi;*.mov;*.AIFF;*.au;*.snd;*.midi;*.mp3;\0");
	
	if( !showOpenDialog( m_hWnd, fileName, tFilter, tInitDir ) )
		return;

	string str,item,dir;
	
	int i;

	for( i = 0; i < MAX_PATH * 4; i++ )
	{
		if( fileName[i] == '\0' )
			fileName[i] = '*';
	}
	for( i = MAX_PATH * 4 - 1; i > 0; i-- )
	{
		if( fileName[i] == '*' )
			fileName[i] = '\0';
		if( fileName[i - 1] != '*' )
			break;
	}

	str = fileName;

	size_t ip;
	ip = str.find_first_of( '*' );
	item = str.substr( 0, ip );
	
	if( ip == str.npos )
		m_vecFile.push_back( FileInfo( item ) );
	else
	{
		dir = item;
		str = str.substr( ip+1 );

		while( (ip = str.find_first_of( '*' ) ) != str.npos )
		{
			item = str.substr( 0, ip );
			m_vecFile.push_back( FileInfo( dir + "\\" + item ) );
			str = str.substr( ip + 1 );
		}
		m_vecFile.push_back( FileInfo( dir + "\\" + str ) );
	}
	PostThreadMessage( GetCurrentThreadId( ), XM_GETFILEINFO, 0, 0 );
}
/////////////////////////////
//获取文件信息
void PlayList::getFileInfo()
{
	vector<FileInfo>::iterator ite;
	LV_ITEM lvi;
	TCHAR tTitle[MAX_PATH];

	int iItem;
	lvi.mask = LVIF_TEXT;
	lvi.iItem = ListView_GetItemCount( m_hWndList );
	lvi.iSubItem = 0;

	for( ite = m_vecFile.begin(); ite != m_vecFile.end(); ite++ )
	{
		if( ite->getInitFlag() )
			continue;

		ite->setInitFlag( true );
		
		_tcscpy( tTitle, ite->getFileName().c_str() );
		lvi.pszText = tTitle;
		lvi.cchTextMax = MAX_PATH;
		iItem = ListView_InsertItem( m_hWndList, &lvi );
		lvi.iItem++;
		ite->setIndex( iItem );
	}

	if( m_curNum == -1 )
	{
		m_curNum = 0;
		ListView_SetHotItem( m_hWndList, m_curNum );
	}
}
//////////////////////////////////
//跳到下一首
void PlayList::gotoNext()
{
	int count = ListView_GetItemCount( m_hWndList );
	if( count == 0 )
	{
		return;
	}

	m_curNum = ListView_GetHotItem( m_hWndList );

	m_curNum++;
	if( m_curNum >= count )
	{
		m_curNum = 0;
	}

	ListView_SetHotItem( m_hWndList, m_curNum );
}
//////////////////////////////////
//跳至上一首
void PlayList::gotoPrev()
{
	int count = ListView_GetItemCount( m_hWndList );
	if( count == 0 )
	{
		return;
	}

	m_curNum = ListView_GetHotItem( m_hWndList );

	m_curNum--;
	if( m_curNum < 0 )
	{
		m_curNum = count - 1;
	}

	ListView_SetHotItem( m_hWndList, m_curNum );
}
//////////////////////////////////
//获取当前用户选择的文件路径
string PlayList::getCurFilePath()
{
	int count = ListView_GetItemCount( m_hWndList );
	if( count == 0 )
	{
		return _T("");
	}

	int curItem = ListView_GetHotItem( m_hWndList );
	
	vector<FileInfo>::iterator ite;

	for( ite = m_vecFile.begin(); ite != m_vecFile.end(); ite++ )
	{
		if( ite->getIndex() == curItem )
		{
			return ite->getPath();
		}
	}
	return _T("");
}
////////////////////////////////////
//删除所选项目
void PlayList::RemSel()
{
	vector<FileInfo>::iterator ite;
	int i;
	int delcount = 0;
	for( ite = m_vecFile.begin(); ite != m_vecFile.end(); ite++ )
	{
		i = ite->getIndex();
		i -= delcount;
		ite->setIndex( i );
		if( ListView_GetItemState( m_hWndList, i, LVIS_SELECTED ) )
		{
			ListView_DeleteItem( m_hWndList, i );
			m_vecFile.erase( ite );
			ite--;
			delcount++;
		}
	}
}
///////////////////////////////////////
//删除未被选择项目
void PlayList::RemUnSel()
{
	vector<FileInfo>::iterator ite;
	int i;
	int delcount = 0;
	for( ite = m_vecFile.begin(); ite != m_vecFile.end(); ite++ )
	{
		i = ite->getIndex();
		i -= delcount;
		ite->setIndex( i );
		if( ! ListView_GetItemState( m_hWndList, i, LVIS_SELECTED ) )
		{
			ListView_DeleteItem( m_hWndList, i );
			m_vecFile.erase( ite );
			ite--;
			delcount++;
		}
	}
}
///////////////////////////////////////
//反选
void PlayList::UnSel()
{
	int count = ListView_GetItemCount( m_hWndList );
	UINT isSel;
	LVITEM lvi;

	for( int i = 0; i < count; i++ )
	{
		isSel =  ListView_GetItemState( m_hWndList, i, LVIS_SELECTED );
		if( isSel )
		{
			lvi.iItem = i;
			lvi.mask = LVIF_STATE;
			lvi.state = 0;
			lvi.stateMask = LVIS_SELECTED;
			ListView_SetItem( m_hWndList, &lvi );
		}
	}
}
///////////////////////////////////////
//选择全部
void PlayList::SelAll()
{
	int count = ListView_GetItemCount( m_hWndList );
	LVITEM lvi;

	for( int i = 0; i < count; i++ )
	{
		lvi.iItem = i;
		lvi.mask = LVIF_STATE;
		lvi.state = LVIS_SELECTED;
		lvi.stateMask = LVIS_SELECTED;
		ListView_SetItem( m_hWndList, &lvi );
	}
}
///////////////////////////////////////
//选择其他
void PlayList::SelOther()
{
	int count = ListView_GetItemCount( m_hWndList );
	UINT isSel;
	LVITEM lvi;

	for( int i = 0; i < count; i++ )
	{
		isSel =  ListView_GetItemState( m_hWndList, i, LVIS_SELECTED );
		if( !isSel )
		{
			lvi.iItem = i;
			lvi.mask = LVIF_STATE;
			lvi.state = LVIS_SELECTED;
			lvi.stateMask = LVIS_SELECTED;
			ListView_SetItem( m_hWndList, &lvi );
		}
		else
		{
			lvi.iItem = i;
			lvi.mask = LVIF_STATE;
			lvi.state = 0;
			lvi.stateMask = LVIS_SELECTED;
			ListView_SetItem( m_hWndList, &lvi );
		}
	}
}